「交差型」のご紹介:Scala 3の新しい型表現(1)

Scala 3.3.4
最終更新:2020年7月8日

[AD] Scalaアプリケーションの開発・保守は合同会社ミルクソフトにお任せください

この記事では、Scala 3(コードネーム:Dotty)にて追加された「交差型」について解説します。

交差型とは「AかつB」を表す型

交差型とは、二つの型の性質を同時に満たすような値のもつ型を表します。

&記号で表します。

例えばAという型とBという型があるとき、A & Bと表すと「AでありかつBでもある型」という意味になります。

実はScala 2においてもwithキーワードを使って似たようなものを表せたのですが、これとの違いについては後述します。

交差型は可換で、共変である

交差型は可換です。つまり、B & AA & Bも同じ型です。

また、共変でもあります。つまり、C[A] & C[B]C[A & B]です。

典型的には、以下のような表現ができるようになりました。これはコンパイルが通ります。

trait A { def children: List[A] } trait B { def children: List[B] } object Main extends App { trait C extends A with B { def children: List[A & B] } val x: A & B = new C { override def children: List[A & B] = List() // filled temporarily } val ys: List[A & B] = x.children }

Scastieで見る

def childrenの戻り値がList[A & B]であることに注目してください。

Scala 2系では「複合型with」で表現していた

交差型ではないですが、Scala 2系には複合型というものがありました(3にもあります)。

複合型はwithキーワードによって定義していました。
使い方はほぼ&と同じです。

ただしScala 2.13においては、先ほどの例をwithで置き換えて同等の表現をしても、コンパイルは通りません。

trait A { def children: List[A] } trait B { def children: List[B] } object Main extends App { trait C extends A with B { def children: List[A with B] } val x: A with B = new C { override def children: List[A with B] = List() } val ys: List[A with B] = x.children // type mismatch; // found : List[B] // required: List[A with B] }

Scastieで見る

複合型は線形化の都合により共変ではなかったので、A with Bと定義したはずのメソッドの戻り値がBになってしまっています。

これこそが複合型の限界でした。

複合型(with)との違い

ただし、Scala 3においてもwithを使った複合型は存続します。

では、どう違うのか、どう使い分けるのか、という点に疑問が生じると思います。この節ではこれについて深掘りしていきます。

2系のwithには二つの意味があり、片方を分離独立させたのが&

withには二つの意味がありました。

  1. 「複数のトレイトを同時に満たしている値の型」という条件を示す表現
    • より抽象的
  2. クラス定義時に複数個のトレイトの実装をどの順番で線形化するかを指示する表現
    • より具体的

抽象度の違うこの両者の識別がわかりにくかったのです。
1.に相当する箇所までもがあたかもB.のように線形化の状態を要求しているかのように見えていました。

1.の部分を分離したのが交差型&です。

しばらくは移行期間;with&に置換される

Scala 3では、しばらくの間は移行期間として、withキーワードも使うことができます。

1.のwithは内部的に&に置換して解釈されます。

2.のwithは引き続きwithとして解釈されます。

交差型の導入は何が嬉しいのか

2系までなら型システムの限界で表現できなかったような型を表現できるようになりました。
つまり「型の表現力が増した」ということです。
Scala言語の開発、あるいはある種のライブラリの開発にとっては生産性が高まるため喜ばしいはずです。

Scalaを活用する一般の開発者にとっては、これといって嬉しいことはないかもしれません。

強いて言えば、「withと書いてあればその箇所で線形化をしている」「&と書いてある場合にはそこでは線形化していない」というのがはっきり見てわかるようになったのが、一般の開発者としては大きいでしょう。

あるいは、&は条件演算子でも「かつ」という意味で用いられているため、交差型でも&を使用することでより読みやすくなった面もあります。

サイト内検索